Clover icon

compiler

  1. Project Clover database Mon Jan 2 2023 15:09:37 MST
  2. Package com.google.javascript.jscomp

File TypedScopeCreator.java

 

Coverage histogram

../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

380
684
65
9
2,087
1,364
371
0.54
10.52
7.22
5.71

Classes

Class Line # Actions
TypedScopeCreator 97 84 19 28
0.7454545574.5%
TypedScopeCreator.DeferredSetType 159 6 2 0
1.0100%
TypedScopeCreator.DiscoverEnumsAndTypedefs 357 19 11 0
1.0100%
TypedScopeCreator.AbstractScopeBuilder 409 450 264 50
0.934469293.4%
TypedScopeCreator.AbstractScopeBuilder.CollectProperties 1719 18 13 0
1.0100%
TypedScopeCreator.StubDeclaration 1774 3 1 0
1.0100%
TypedScopeCreator.GlobalScopeBuilder 1790 21 11 4
0.885714388.6%
TypedScopeCreator.LocalScopeBuilder 1867 51 27 6
0.931818293.2%
TypedScopeCreator.FirstOrderFunctionAnalyzer 1997 32 23 4
0.9333333493.3%
 

Contributing tests

This file is covered by 6554 tests. .

Source view

1    /*
2    * Copyright 2004 The Closure Compiler Authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10    * Unless required by applicable law or agreed to in writing, software
11    * distributed under the License is distributed on an "AS IS" BASIS,
12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    * See the License for the specific language governing permissions and
14    * limitations under the License.
15    */
16   
17    package com.google.javascript.jscomp;
18   
19    import static com.google.javascript.jscomp.TypeCheck.ENUM_NOT_CONSTANT;
20    import static com.google.javascript.jscomp.TypeCheck.MULTIPLE_VAR_DEF;
21    import static com.google.javascript.rhino.jstype.JSTypeNative.ARRAY_FUNCTION_TYPE;
22    import static com.google.javascript.rhino.jstype.JSTypeNative.BOOLEAN_OBJECT_FUNCTION_TYPE;
23    import static com.google.javascript.rhino.jstype.JSTypeNative.BOOLEAN_TYPE;
24    import static com.google.javascript.rhino.jstype.JSTypeNative.DATE_FUNCTION_TYPE;
25    import static com.google.javascript.rhino.jstype.JSTypeNative.ERROR_FUNCTION_TYPE;
26    import static com.google.javascript.rhino.jstype.JSTypeNative.EVAL_ERROR_FUNCTION_TYPE;
27    import static com.google.javascript.rhino.jstype.JSTypeNative.FUNCTION_FUNCTION_TYPE;
28    import static com.google.javascript.rhino.jstype.JSTypeNative.FUNCTION_INSTANCE_TYPE;
29    import static com.google.javascript.rhino.jstype.JSTypeNative.GLOBAL_THIS;
30    import static com.google.javascript.rhino.jstype.JSTypeNative.NO_TYPE;
31    import static com.google.javascript.rhino.jstype.JSTypeNative.NULL_TYPE;
32    import static com.google.javascript.rhino.jstype.JSTypeNative.NUMBER_OBJECT_FUNCTION_TYPE;
33    import static com.google.javascript.rhino.jstype.JSTypeNative.NUMBER_TYPE;
34    import static com.google.javascript.rhino.jstype.JSTypeNative.OBJECT_FUNCTION_TYPE;
35    import static com.google.javascript.rhino.jstype.JSTypeNative.OBJECT_TYPE;
36    import static com.google.javascript.rhino.jstype.JSTypeNative.RANGE_ERROR_FUNCTION_TYPE;
37    import static com.google.javascript.rhino.jstype.JSTypeNative.REFERENCE_ERROR_FUNCTION_TYPE;
38    import static com.google.javascript.rhino.jstype.JSTypeNative.REGEXP_FUNCTION_TYPE;
39    import static com.google.javascript.rhino.jstype.JSTypeNative.REGEXP_TYPE;
40    import static com.google.javascript.rhino.jstype.JSTypeNative.STRING_OBJECT_FUNCTION_TYPE;
41    import static com.google.javascript.rhino.jstype.JSTypeNative.STRING_TYPE;
42    import static com.google.javascript.rhino.jstype.JSTypeNative.SYNTAX_ERROR_FUNCTION_TYPE;
43    import static com.google.javascript.rhino.jstype.JSTypeNative.TYPE_ERROR_FUNCTION_TYPE;
44    import static com.google.javascript.rhino.jstype.JSTypeNative.U2U_CONSTRUCTOR_TYPE;
45    import static com.google.javascript.rhino.jstype.JSTypeNative.UNKNOWN_TYPE;
46    import static com.google.javascript.rhino.jstype.JSTypeNative.URI_ERROR_FUNCTION_TYPE;
47    import static com.google.javascript.rhino.jstype.JSTypeNative.VOID_TYPE;
48   
49    import com.google.common.annotations.VisibleForTesting;
50    import com.google.common.base.Preconditions;
51    import com.google.common.collect.ImmutableList;
52    import com.google.common.collect.Lists;
53    import com.google.common.collect.Maps;
54    import com.google.common.collect.Multiset;
55    import com.google.javascript.jscomp.CodingConvention.DelegateRelationship;
56    import com.google.javascript.jscomp.CodingConvention.ObjectLiteralCast;
57    import com.google.javascript.jscomp.CodingConvention.SubclassRelationship;
58    import com.google.javascript.jscomp.CodingConvention.SubclassType;
59    import com.google.javascript.jscomp.FunctionTypeBuilder.AstFunctionContents;
60    import com.google.javascript.jscomp.NodeTraversal.AbstractScopedCallback;
61    import com.google.javascript.jscomp.NodeTraversal.AbstractShallowStatementCallback;
62    import com.google.javascript.jscomp.Scope.Var;
63    import com.google.javascript.rhino.ErrorReporter;
64    import com.google.javascript.rhino.InputId;
65    import com.google.javascript.rhino.JSDocInfo;
66    import com.google.javascript.rhino.Node;
67    import com.google.javascript.rhino.Token;
68    import com.google.javascript.rhino.jstype.EnumType;
69    import com.google.javascript.rhino.jstype.FunctionParamBuilder;
70    import com.google.javascript.rhino.jstype.FunctionType;
71    import com.google.javascript.rhino.jstype.JSType;
72    import com.google.javascript.rhino.jstype.JSTypeNative;
73    import com.google.javascript.rhino.jstype.JSTypeRegistry;
74    import com.google.javascript.rhino.jstype.ObjectType;
75    import com.google.javascript.rhino.jstype.Property;
76   
77    import java.util.Iterator;
78    import java.util.List;
79    import java.util.Map;
80   
81    import javax.annotation.Nullable;
82   
83    /**
84    * Creates the symbol table of variables available in the current scope and
85    * their types.
86    *
87    * Scopes created by this class are very different from scopes created
88    * by the syntactic scope creator. These scopes have type information, and
89    * include some qualified names in addition to variables
90    * (like Class.staticMethod).
91    *
92    * When building scope information, also declares relevant information
93    * about types in the type registry.
94    *
95    * @author nicksantos@google.com (Nick Santos)
96    */
 
97    final class TypedScopeCreator implements ScopeCreator {
98    /**
99    * A suffix for naming delegate proxies differently from their base.
100    */
101    static final String DELEGATE_PROXY_SUFFIX =
102    ObjectType.createDelegateSuffix("Proxy");
103   
104    static final DiagnosticType MALFORMED_TYPEDEF =
105    DiagnosticType.warning(
106    "JSC_MALFORMED_TYPEDEF",
107    "Typedef for {0} does not have any type information");
108   
109    static final DiagnosticType ENUM_INITIALIZER =
110    DiagnosticType.warning(
111    "JSC_ENUM_INITIALIZER_NOT_ENUM",
112    "enum initializer must be an object literal or an enum");
113   
114    static final DiagnosticType CTOR_INITIALIZER =
115    DiagnosticType.warning(
116    "JSC_CTOR_INITIALIZER_NOT_CTOR",
117    "Constructor {0} must be initialized at declaration");
118   
119    static final DiagnosticType IFACE_INITIALIZER =
120    DiagnosticType.warning(
121    "JSC_IFACE_INITIALIZER_NOT_IFACE",
122    "Interface {0} must be initialized at declaration");
123   
124    static final DiagnosticType CONSTRUCTOR_EXPECTED =
125    DiagnosticType.warning(
126    "JSC_REFLECT_CONSTRUCTOR_EXPECTED",
127    "Constructor expected as first argument");
128   
129    static final DiagnosticType UNKNOWN_LENDS =
130    DiagnosticType.warning(
131    "JSC_UNKNOWN_LENDS",
132    "Variable {0} not declared before @lends annotation.");
133   
134    static final DiagnosticType LENDS_ON_NON_OBJECT =
135    DiagnosticType.warning(
136    "JSC_LENDS_ON_NON_OBJECT",
137    "May only lend properties to object types. {0} has type {1}.");
138   
139    private final AbstractCompiler compiler;
140    private final ErrorReporter typeParsingErrorReporter;
141    private final TypeValidator validator;
142    private final CodingConvention codingConvention;
143    private final JSTypeRegistry typeRegistry;
144    private final List<ObjectType> delegateProxyPrototypes = Lists.newArrayList();
145    private final Map<String, String> delegateCallingConventions =
146    Maps.newHashMap();
147   
148    // Simple properties inferred about functions.
149    private final Map<Node, AstFunctionContents> functionAnalysisResults =
150    Maps.newHashMap();
151   
152    // For convenience
153    private final ObjectType unknownType;
154   
155    /**
156    * Defer attachment of types to nodes until all type names
157    * have been resolved. Then, we can resolve the type and attach it.
158    */
 
159    private class DeferredSetType {
160    final Node node;
161    final JSType type;
162   
 
163  180021 toggle DeferredSetType(Node node, JSType type) {
164  180021 Preconditions.checkNotNull(node);
165  180021 Preconditions.checkNotNull(type);
166  180021 this.node = node;
167  180021 this.type = type;
168   
169    // Other parts of this pass may read off the node.
170    // (like when we set the LHS of an assign with a typed RHS function.)
171  180021 node.setJSType(type);
172    }
173   
 
174  180021 toggle void resolve(Scope scope) {
175  180021 node.setJSType(type.resolve(typeParsingErrorReporter, scope));
176    }
177    }
178   
 
179  7170 toggle TypedScopeCreator(AbstractCompiler compiler) {
180  7170 this(compiler, compiler.getCodingConvention());
181    }
182   
 
183  7175 toggle TypedScopeCreator(AbstractCompiler compiler,
184    CodingConvention codingConvention) {
185  7175 this.compiler = compiler;
186  7175 this.validator = compiler.getTypeValidator();
187  7175 this.codingConvention = codingConvention;
188  7175 this.typeRegistry = compiler.getTypeRegistry();
189  7175 this.typeParsingErrorReporter = typeRegistry.getErrorReporter();
190  7175 this.unknownType = typeRegistry.getNativeObjectType(UNKNOWN_TYPE);
191    }
192   
193    /**
194    * Creates a scope with all types declared. Declares newly discovered types
195    * and type properties in the type registry.
196    */
 
197  65668 toggle @Override
198    public Scope createScope(Node root, Scope parent) {
199    // Constructing the global scope is very different than constructing
200    // inner scopes, because only global scopes can contain named classes that
201    // show up in the type registry.
202  65668 Scope newScope = null;
203  65668 AbstractScopeBuilder scopeBuilder = null;
204  65668 if (parent == null) {
205  7176 JSType globalThis =
206    typeRegistry.getNativeObjectType(JSTypeNative.GLOBAL_THIS);
207   
208    // Mark the main root, the externs root, and the src root
209    // with the global this type.
210  7176 root.setJSType(globalThis);
211  7176 root.getFirstChild().setJSType(globalThis);
212  7176 root.getLastChild().setJSType(globalThis);
213   
214    // Run a first-order analysis over the syntax tree.
215  7176 (new FirstOrderFunctionAnalyzer(compiler, functionAnalysisResults))
216    .process(root.getFirstChild(), root.getLastChild());
217   
218    // Find all the classes in the global scope.
219  7176 newScope = createInitialScope(root);
220   
221  7176 GlobalScopeBuilder globalScopeBuilder = new GlobalScopeBuilder(newScope);
222  7176 scopeBuilder = globalScopeBuilder;
223  7176 NodeTraversal.traverse(compiler, root, scopeBuilder);
224    } else {
225  58492 newScope = new Scope(parent, root);
226  58492 LocalScopeBuilder localScopeBuilder = new LocalScopeBuilder(newScope);
227  58492 scopeBuilder = localScopeBuilder;
228  58492 localScopeBuilder.build();
229    }
230   
231  65668 scopeBuilder.resolveStubDeclarations();
232  65668 scopeBuilder.resolveTypes();
233   
234    // Gather the properties in each function that we found in the
235    // global scope, if that function has a @this type that we can
236    // build properties on.
237  65668 for (Node functionNode : scopeBuilder.nonExternFunctions) {
238  12484 JSType type = functionNode.getJSType();
239  12484 if (type != null && type.isFunctionType()) {
240  12484 FunctionType fnType = type.toMaybeFunctionType();
241  12484 JSType fnThisType = fnType.getTypeOfThis();
242  12484 if (!fnThisType.isUnknownType()) {
243  6126 NodeTraversal.traverse(compiler, functionNode.getLastChild(),
244    scopeBuilder.new CollectProperties(fnThisType));
245    }
246    }
247    }
248   
249  65668 if (parent == null) {
250  7176 codingConvention.defineDelegateProxyPrototypeProperties(
251    typeRegistry, newScope, delegateProxyPrototypes,
252    delegateCallingConventions);
253    }
254  65668 return newScope;
255    }
256   
257    /**
258    * Patches a given global scope by removing variables previously declared in
259    * a script and re-traversing a new version of that script.
260    *
261    * @param globalScope The global scope generated by {@code createScope}.
262    * @param scriptRoot The script that is modified.
263    */
 
264  0 toggle void patchGlobalScope(Scope globalScope, Node scriptRoot) {
265    // Preconditions: This is supposed to be called only on (named) SCRIPT nodes
266    // and a global typed scope should have been generated already.
267  0 Preconditions.checkState(scriptRoot.isScript());
268  0 Preconditions.checkNotNull(globalScope);
269  0 Preconditions.checkState(globalScope.isGlobal());
270   
271  0 String scriptName = NodeUtil.getSourceName(scriptRoot);
272  0 Preconditions.checkNotNull(scriptName);
273  0 for (Node node : ImmutableList.copyOf(functionAnalysisResults.keySet())) {
274  0 if (scriptName.equals(NodeUtil.getSourceName(node))) {
275  0 functionAnalysisResults.remove(node);
276    }
277    }
278   
279  0 (new FirstOrderFunctionAnalyzer(
280    compiler, functionAnalysisResults)).process(null, scriptRoot);
281   
282    // TODO(bashir): Variable declaration is not the only side effect of last
283    // global scope generation but here we only wipe that part off!
284   
285    // Remove all variables that were previously declared in this scripts.
286    // First find all vars to remove then remove them because of iterator!
287  0 Iterator<Var> varIter = globalScope.getVars();
288  0 List<Var> varsToRemove = Lists.newArrayList();
289  0 while (varIter.hasNext()) {
290  0 Var oldVar = varIter.next();
291  0 if (scriptName.equals(oldVar.getInputName())) {
292  0 varsToRemove.add(oldVar);
293    }
294    }
295  0 for (Var var : varsToRemove) {
296  0 globalScope.undeclare(var);
297  0 globalScope.getTypeOfThis().toObjectType().removeProperty(var.getName());
298    }
299   
300    // Now re-traverse the given script.
301  0 GlobalScopeBuilder scopeBuilder = new GlobalScopeBuilder(globalScope);
302  0 NodeTraversal.traverse(compiler, scriptRoot, scopeBuilder);
303    }
304   
305    /**
306    * Create the outermost scope. This scope contains native binding such as
307    * {@code Object}, {@code Date}, etc.
308    */
 
309  7181 toggle @VisibleForTesting
310    Scope createInitialScope(Node root) {
311   
312  7181 NodeTraversal.traverse(
313    compiler, root, new DiscoverEnumsAndTypedefs(typeRegistry));
314   
315  7181 Scope s = Scope.createGlobalScope(root);
316  7181 declareNativeFunctionType(s, ARRAY_FUNCTION_TYPE);
317  7181 declareNativeFunctionType(s, BOOLEAN_OBJECT_FUNCTION_TYPE);
318  7181 declareNativeFunctionType(s, DATE_FUNCTION_TYPE);
319  7181 declareNativeFunctionType(s, ERROR_FUNCTION_TYPE);
320  7181 declareNativeFunctionType(s, EVAL_ERROR_FUNCTION_TYPE);
321  7181 declareNativeFunctionType(s, FUNCTION_FUNCTION_TYPE);
322  7181 declareNativeFunctionType(s, NUMBER_OBJECT_FUNCTION_TYPE);
323  7181 declareNativeFunctionType(s, OBJECT_FUNCTION_TYPE);
324  7181 declareNativeFunctionType(s, RANGE_ERROR_FUNCTION_TYPE);
325  7181 declareNativeFunctionType(s, REFERENCE_ERROR_FUNCTION_TYPE);
326  7181 declareNativeFunctionType(s, REGEXP_FUNCTION_TYPE);
327  7181 declareNativeFunctionType(s, STRING_OBJECT_FUNCTION_TYPE);
328  7181 declareNativeFunctionType(s, SYNTAX_ERROR_FUNCTION_TYPE);
329  7181 declareNativeFunctionType(s, TYPE_ERROR_FUNCTION_TYPE);
330  7181 declareNativeFunctionType(s, URI_ERROR_FUNCTION_TYPE);
331  7181 declareNativeValueType(s, "undefined", VOID_TYPE);
332   
333    // There is no longer a need to special case ActiveXObject
334    // but this remains here until we can get the extern forks
335    // cleaned up.
336  7181 declareNativeValueType(s, "ActiveXObject", FUNCTION_INSTANCE_TYPE);
337   
338  7181 return s;
339    }
340   
 
341  107715 toggle private void declareNativeFunctionType(Scope scope, JSTypeNative tId) {
342  107715 FunctionType t = typeRegistry.getNativeFunctionType(tId);
343  107715 declareNativeType(scope, t.getInstanceType().getReferenceName(), t);
344  107715 declareNativeType(
345    scope, t.getPrototype().getReferenceName(), t.getPrototype());
346    }
347   
 
348  14362 toggle private void declareNativeValueType(Scope scope, String name,
349    JSTypeNative tId) {
350  14362 declareNativeType(scope, name, typeRegistry.getNativeType(tId));
351    }
352   
 
353  229792 toggle private void declareNativeType(Scope scope, String name, JSType t) {
354  229792 scope.declare(name, null, t, null, false);
355    }
356   
 
357    private static class DiscoverEnumsAndTypedefs
358    extends AbstractShallowStatementCallback {
359    private final JSTypeRegistry registry;
360   
 
361  7181 toggle DiscoverEnumsAndTypedefs(JSTypeRegistry registry) {
362  7181 this.registry = registry;
363    }
364   
 
365  134110 toggle @Override
366    public void visit(NodeTraversal t, Node node, Node parent) {
367  134110 Node nameNode = null;
368  134110 switch (node.getType()) {
369  12843 case Token.VAR:
370  12843 for (Node child = node.getFirstChild();
371  25708 child != null; child = child.getNext()) {
372  12865 identifyNameNode(
373    child, child.getFirstChild(),
374    NodeUtil.getBestJSDocInfo(child));
375    }
376  12843 break;
377  52697 case Token.EXPR_RESULT:
378  52697 Node firstChild = node.getFirstChild();
379  52697 if (firstChild.isAssign()) {
380  16706 identifyNameNode(
381    firstChild.getFirstChild(), firstChild.getLastChild(),
382    firstChild.getJSDocInfo());
383    } else {
384  35991 identifyNameNode(
385    firstChild, null, firstChild.getJSDocInfo());
386    }
387  52697 break;
388    }
389    }
390   
 
391  65562 toggle private void identifyNameNode(
392    Node nameNode, Node valueNode, JSDocInfo info) {
393  65562 if (nameNode.isQualifiedName()) {
394  63227 if (info != null) {
395  49732 if (info.hasEnumParameterType()) {
396  419 registry.identifyNonNullableName(nameNode.getQualifiedName());
397  49313 } else if (info.hasTypedefType()) {
398  182 registry.identifyNonNullableName(nameNode.getQualifiedName());
399    }
400    }
401    }
402    }
403    }
404   
 
405  142424 toggle private JSType getNativeType(JSTypeNative nativeType) {
406  142424 return typeRegistry.getNativeType(nativeType);
407    }
408   
 
409    private abstract class AbstractScopeBuilder
410    implements NodeTraversal.Callback {
411   
412    /**
413    * The scope that we're building.
414    */
415    final Scope scope;
416   
417    private final List<DeferredSetType> deferredSetTypes =
418    Lists.newArrayList();
419   
420    /**
421    * Functions that we found in the global scope and not in externs.
422    */
423    private final List<Node> nonExternFunctions = Lists.newArrayList();
424   
425    /**
426    * Object literals with a @lends annotation aren't analyzed until we
427    * reach the root of the statement they're defined in.
428    *
429    * This ensures that if there are any @lends annotations on the object
430    * literals, the type on the @lends annotation resolves correctly.
431    *
432    * For more information, see
433    * http://code.google.com/p/closure-compiler/issues/detail?id=314
434    */
435    private List<Node> lentObjectLiterals = null;
436   
437    /**
438    * Type-less stubs.
439    *
440    * If at the end of traversal, we still don't have types for these
441    * stubs, then we should declare UNKNOWN types.
442    */
443    private final List<StubDeclaration> stubDeclarations =
444    Lists.newArrayList();
445   
446    /**
447    * The current source file that we're in.
448    */
449    private String sourceName = null;
450   
451    /**
452    * The InputId of the current node.
453    */
454    private InputId inputId;
455   
 
456  65668 toggle private AbstractScopeBuilder(Scope scope) {
457  65668 this.scope = scope;
458    }
459   
 
460  180021 toggle void setDeferredType(Node node, JSType type) {
461  180021 deferredSetTypes.add(new DeferredSetType(node, type));
462    }
463   
 
464  65668 toggle void resolveTypes() {
465    // Resolve types and attach them to nodes.
466  65668 for (DeferredSetType deferred : deferredSetTypes) {
467  180021 deferred.resolve(scope);
468    }
469   
470    // Resolve types and attach them to scope slots.
471  65668 Iterator<Var> vars = scope.getVars();
472  433812 while (vars.hasNext()) {
473  368144 vars.next().resolveType(typeParsingErrorReporter);
474    }
475   
476    // Tell the type registry that any remaining types
477    // are unknown.
478  65668 typeRegistry.resolveTypesInScope(scope);
479    }
480   
 
481  930489 toggle @Override
482    public final boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
483  930489 inputId = t.getInputId();
484  930489 if (n.isFunction() ||
485    n.isScript()) {
486  130911 Preconditions.checkNotNull(inputId);
487  130911 sourceName = NodeUtil.getSourceName(n);
488    }
489   
490    // We do want to traverse the name of a named function, but we don't
491    // want to traverse the arguments or body.
492  930489 boolean descend = parent == null || !parent.isFunction() ||
493    n == parent.getFirstChild() || parent == scope.getRootNode();
494   
495  930489 if (descend) {
496    // Handle hoisted functions on pre-order traversal, so that they
497    // get hit before other things in the scope.
498  813407 if (NodeUtil.isStatementParent(n)) {
499  85304 for (Node child = n.getFirstChild();
500  219688 child != null;
501    child = child.getNext()) {
502  134384 if (NodeUtil.isHoistedFunctionDeclaration(child)) {
503  41334 defineFunctionLiteral(child);
504    }
505    }
506    }
507    }
508   
509  930489 return descend;
510    }
511   
 
512  696423 toggle @Override
513    public void visit(NodeTraversal t, Node n, Node parent) {
514  696423 inputId = t.getInputId();
515  696423 attachLiteralTypes(t, n);
516   
517  696423 switch (n.getType()) {
518  3382 case Token.CALL:
519  3382 checkForClassDefiningCalls(t, n, parent);
520  3382 checkForCallingConventionDefiningCalls(n, delegateCallingConventions);
521  3382 break;
522   
523  58541 case Token.FUNCTION:
524  58541 if (t.getInput() == null || !t.getInput().isExtern()) {
525  12484 nonExternFunctions.add(n);
526    }
527   
528    // Hoisted functions are handled during pre-traversal.
529  58541 if (!NodeUtil.isHoistedFunctionDeclaration(n)) {
530  17207 defineFunctionLiteral(n);
531    }
532  58541 break;
533   
534  19178 case Token.ASSIGN:
535    // Handle initialization of properties.
536  19178 Node firstChild = n.getFirstChild();
537  19178 if (firstChild.isGetProp() &&
538    firstChild.isQualifiedName()) {
539  17193 maybeDeclareQualifiedName(t, n.getJSDocInfo(),
540    firstChild, n, firstChild.getNext());
541    }
542  19178 break;
543   
544  29 case Token.CATCH:
545  29 defineCatch(n);
546  29 break;
547   
548  13598 case Token.VAR:
549  13598 defineVar(n);
550  13598 break;
551   
552  99698 case Token.GETPROP:
553    // Handle stubbed properties.
554  99698 if (parent.isExprResult() &&
555    n.isQualifiedName()) {
556  33832 maybeDeclareQualifiedName(t, n.getJSDocInfo(), n, parent, null);
557    }
558  99698 break;
559    }
560   
561    // Analyze any @lends object literals in this statement.
562  696423 if (n.getParent() != null && NodeUtil.isStatement(n) &&
563    lentObjectLiterals != null) {
564  54 for (Node objLit : lentObjectLiterals) {
565  20 defineObjectLiteral(objLit);
566    }
567  54 lentObjectLiterals.clear();
568    }
569    }
570   
 
571  696423 toggle private void attachLiteralTypes(NodeTraversal t, Node n) {
572  696423 switch (n.getType()) {
573  631 case Token.NULL:
574  631 n.setJSType(getNativeType(NULL_TYPE));
575  631 break;
576   
577  30 case Token.VOID:
578  30 n.setJSType(getNativeType(VOID_TYPE));
579  30 break;
580   
581  101829 case Token.STRING:
582  101829 n.setJSType(getNativeType(STRING_TYPE));
583  101829 break;
584   
585  4861 case Token.NUMBER:
586  4861 n.setJSType(getNativeType(NUMBER_TYPE));
587  4861 break;
588   
589  345 case Token.TRUE:
590  84 case Token.FALSE:
591  429 n.setJSType(getNativeType(BOOLEAN_TYPE));
592  429 break;
593   
594  14 case Token.REGEXP:
595  14 n.setJSType(getNativeType(REGEXP_TYPE));
596  14 break;
597   
598  2995 case Token.OBJECTLIT:
599  2995 JSDocInfo info = n.getJSDocInfo();
600  2995 if (info != null &&
601    info.getLendsName() != null) {
602  20 if (lentObjectLiterals == null) {
603  20 lentObjectLiterals = Lists.newArrayList();
604    }
605  20 lentObjectLiterals.add(n);
606    } else {
607  2975 defineObjectLiteral(n);
608    }
609  2995 break;
610   
611    // NOTE(nicksantos): If we ever support Array tuples,
612    // we will need to put ARRAYLIT here as well.
613    }
614    }
615   
 
616  2995 toggle private void defineObjectLiteral(Node objectLit) {
617    // Handle the @lends annotation.
618  2995 JSType type = null;
619  2995 JSDocInfo info = objectLit.getJSDocInfo();
620  2995 if (info != null && info.getLendsName() != null) {
621  20 String lendsName = info.getLendsName();
622  20 Var lendsVar = scope.getVar(lendsName);
623  20 if (lendsVar == null) {
624  2 compiler.report(
625    JSError.make(sourceName, objectLit, UNKNOWN_LENDS, lendsName));
626    } else {
627  18 type = lendsVar.getType();
628  18 if (type == null) {
629  0 type = unknownType;
630    }
631  18 if (!type.isSubtype(typeRegistry.getNativeType(OBJECT_TYPE))) {
632  2 compiler.report(
633    JSError.make(sourceName, objectLit, LENDS_ON_NON_OBJECT,
634    lendsName, type.toString()));
635  2 type = null;
636    } else {
637  16 objectLit.setJSType(type);
638    }
639    }
640    }
641   
642  2995 info = NodeUtil.getBestJSDocInfo(objectLit);
643  2995 Node lValue = NodeUtil.getBestLValue(objectLit);
644  2995 String lValueName = NodeUtil.getBestLValueName(lValue);
645  2995 boolean createdEnumType = false;
646  2995 if (info != null && info.hasEnumParameterType()) {
647  340 type = createEnumTypeFromNodes(objectLit, lValueName, info, lValue);
648  340 createdEnumType = true;
649    }
650   
651  2995 if (type == null) {
652  2639 type = typeRegistry.createAnonymousObjectType(info);
653    }
654   
655  2995 setDeferredType(objectLit, type);
656   
657    // If this is an enum, the properties were already taken care of above.
658  2995 processObjectLitProperties(
659    objectLit, ObjectType.cast(objectLit.getJSType()), !createdEnumType);
660    }
661   
662    /**
663    * Process an object literal and all the types on it.
664    * @param objLit The OBJECTLIT node.
665    * @param objLitType The type of the OBJECTLIT node. This might be a named
666    * type, because of the lends annotation.
667    * @param declareOnOwner If true, declare properties on the objLitType as
668    * well. If false, the caller should take care of this.
669    */
 
670  2995 toggle void processObjectLitProperties(
671    Node objLit, ObjectType objLitType,
672    boolean declareOnOwner) {
673  4434 for (Node keyNode = objLit.getFirstChild(); keyNode != null;
674    keyNode = keyNode.getNext()) {
675  1439 Node value = keyNode.getFirstChild();
676  1439 String memberName = NodeUtil.getObjectLitKeyName(keyNode);
677  1439 JSDocInfo info = keyNode.getJSDocInfo();
678  1439 JSType valueType =
679    getDeclaredType(keyNode.getSourceFileName(), info, keyNode, value);
680  1439 JSType keyType = objLitType.isEnumType() ?
681    objLitType.toMaybeEnumType().getElementsType() :
682    NodeUtil.getObjectLitKeyTypeFromValueType(keyNode, valueType);
683   
684    // Try to declare this property in the current scope if it
685    // has an authoritative name.
686  1439 String qualifiedName = NodeUtil.getBestLValueName(keyNode);
687  1439 if (qualifiedName != null) {
688  1367 boolean inferred = keyType == null;
689  1367 defineSlot(keyNode, objLit, qualifiedName, keyType, inferred);
690  72 } else if (keyType != null) {
691  9 setDeferredType(keyNode, keyType);
692    }
693   
694  1439 if (keyType != null && objLitType != null && declareOnOwner) {
695    // Declare this property on its object literal.
696  99 boolean isExtern = keyNode.isFromExterns();
697  99 objLitType.defineDeclaredProperty(memberName, keyType, keyNode);
698    }
699    }
700    }
701   
702    /**
703    * Returns the type specified in a JSDoc annotation near a GETPROP or NAME.
704    *
705    * Extracts type information from either the {@code @type} tag or from
706    * the {@code @return} and {@code @param} tags.
707    */
 
708  49329 toggle private JSType getDeclaredTypeInAnnotation(String sourceName,
709    Node node, JSDocInfo info) {
710  49329 JSType jsType = null;
711  49329 Node objNode =
712  49329 node.isGetProp() ? node.getFirstChild() :
713  12448 NodeUtil.isObjectLitKey(node, node.getParent()) ? node.getParent() :
714    null;
715  49329 if (info != null) {
716  39110 if (info.hasType()) {
717  38275 jsType = info.getType().evaluate(scope, typeRegistry);
718  835 } else if (FunctionTypeBuilder.isFunctionTypeDeclaration(info)) {
719  152 String fnName = node.getQualifiedName();
720  152 jsType = createFunctionTypeFromNodes(
721    null, fnName, info, node);
722    }
723    }
724  49329 return jsType;
725    }
726   
727    /**
728    * Asserts that it's OK to define this node's name.
729    * The node should have a source name and be of the specified type.
730    */
 
731  72168 toggle void assertDefinitionNode(Node n, int type) {
732  72168 Preconditions.checkState(sourceName != null);
733  72168 Preconditions.checkState(n.getType() == type);
734    }
735   
736    /**
737    * Defines a catch parameter.
738    */
 
739  29 toggle void defineCatch(Node n) {
740  29 assertDefinitionNode(n, Token.CATCH);
741  29 Node catchName = n.getFirstChild();
742  29 defineSlot(catchName, n,
743    getDeclaredType(
744    sourceName, catchName.getJSDocInfo(), catchName, null));
745    }
746   
747    /**
748    * Defines a VAR initialization.
749    */
 
750  13598 toggle void defineVar(Node n) {
751  13598 assertDefinitionNode(n, Token.VAR);
752  13598 JSDocInfo info = n.getJSDocInfo();
753  13598 if (n.hasMoreThanOneChild()) {
754  22 if (info != null) {
755    // multiple children
756  5 compiler.report(JSError.make(sourceName, n, MULTIPLE_VAR_DEF));
757    }
758  22 for (Node name : n.children()) {
759  44 defineName(name, n, name.getJSDocInfo());
760    }
761    } else {
762  13576 Node name = n.getFirstChild();
763  13576 defineName(name, n, (info != null) ? info : name.getJSDocInfo());
764    }
765    }
766   
767    /**
768    * Defines a function literal.
769    */
 
770  58541 toggle void defineFunctionLiteral(Node n) {
771  58541 assertDefinitionNode(n, Token.FUNCTION);
772   
773    // Determine the name and JSDocInfo and l-value for the function.
774    // Any of these may be null.
775  58541 Node lValue = NodeUtil.getBestLValue(n);
776  58541 JSDocInfo info = NodeUtil.getBestJSDocInfo(n);
777  58541 String functionName = NodeUtil.getBestLValueName(lValue);
778  58541 FunctionType functionType =
779    createFunctionTypeFromNodes(n, functionName, info, lValue);
780   
781    // Assigning the function type to the function node
782  58541 setDeferredType(n, functionType);
783   
784    // Declare this symbol in the current scope iff it's a function
785    // declaration. Otherwise, the declaration will happen in other
786    // code paths.
787  58541 if (NodeUtil.isFunctionDeclaration(n)) {
788  41348 defineSlot(n.getFirstChild(), n, functionType);
789    }
790    }
791   
792    /**
793    * Defines a variable based on the {@link Token#NAME} node passed.
794    * @param name The {@link Token#NAME} node.
795    * @param var The parent of the {@code name} node, which must be a
796    * {@link Token#VAR} node.
797    * @param info the {@link JSDocInfo} information relating to this
798    * {@code name} node.
799    */
 
800  13620 toggle private void defineName(Node name, Node var, JSDocInfo info) {
801  13620 Node value = name.getFirstChild();
802   
803    // variable's type
804  13620 JSType type = getDeclaredType(sourceName, info, name, value);
805  13620 if (type == null) {
806    // The variable's type will be inferred.
807  3943 type = name.isFromExterns() ? unknownType : null;
808    }
809  13620 defineSlot(name, var, type);
810    }
811   
812    /**
813    * If a variable is assigned a function literal in the global scope,
814    * make that a declared type (even if there's no doc info).
815    * There's only one exception to this rule:
816    * if the return type is inferred, and we're in a local
817    * scope, we should assume the whole function is inferred.
818    */
 
819  16449 toggle private boolean shouldUseFunctionLiteralType(
820    FunctionType type, JSDocInfo info, Node lValue) {
821  16449 if (info != null) {
822  10571 return true;
823    }
824  5878 if (lValue != null &&
825    NodeUtil.isObjectLitKey(lValue, lValue.getParent())) {
826  106 return false;
827    }
828  5772 return scope.isGlobal() || !type.isReturnTypeInferred();
829    }
830   
831    /**
832    * Creates a new function type, based on the given nodes.
833    *
834    * This handles two cases that are semantically very different, but
835    * are not mutually exclusive:
836    * - A function literal that needs a type attached to it.
837    * - An assignment expression with function-type info in the JsDoc.
838    *
839    * All parameters are optional, and we will do the best we can to create
840    * a function type.
841    *
842    * This function will always create a function type, so only call it if
843    * you're sure that's what you want.
844    *
845    * @param rValue The function node.
846    * @param name the function's name
847    * @param info the {@link JSDocInfo} attached to the function definition
848    * @param lvalueNode The node where this function is being
849    * assigned. For example, {@code A.prototype.foo = ...} would be used to
850    * determine that this function is a method of A.prototype. May be
851    * null to indicate that this is not being assigned to a qualified name.
852    */
 
853  58808 toggle private FunctionType createFunctionTypeFromNodes(
854    @Nullable Node rValue,
855    @Nullable String name,
856    @Nullable JSDocInfo info,
857    @Nullable Node lvalueNode) {
858   
859  58808 FunctionType functionType = null;
860   
861    // Global ctor aliases should be registered with the type registry.
862  58808 if (rValue != null && rValue.isQualifiedName() && scope.isGlobal()) {
863  72 Var var = scope.getVar(rValue.getQualifiedName());
864  72 if (var != null && var.getType() != null &&
865    var.getType().isFunctionType()) {
866  72 FunctionType aliasedType = var.getType().toMaybeFunctionType();
867  72 if ((aliasedType.isConstructor() || aliasedType.isInterface()) &&
868    !aliasedType.isNativeObjectType()) {
869  68 functionType = aliasedType;
870   
871  68 if (name != null && scope.isGlobal()) {
872  68 typeRegistry.declareType(name, functionType.getInstanceType());
873    }
874    }
875    }
876    }
877   
878  58808 if (functionType == null) {
879  58740 Node errorRoot = rValue == null ? lvalueNode : rValue;
880  58740 boolean isFnLiteral =
881    rValue != null && rValue.isFunction();
882  58740 Node fnRoot = isFnLiteral ? rValue : null;
883  58740 Node parametersNode = isFnLiteral ?
884    rValue.getFirstChild().getNext() : null;
885  58740 Node fnBlock = isFnLiteral ? parametersNode.getNext() : null;
886   
887  58740 if (info != null && info.hasType()) {
888  245 JSType type = info.getType().evaluate(scope, typeRegistry);
889   
890    // Known to be not null since we have the FUNCTION token there.
891  245 type = type.restrictByNotNullOrUndefined();
892  245 if (type.isFunctionType()) {
893  229 functionType = type.toMaybeFunctionType();
894  229 functionType.setJSDocInfo(info);
895    }
896    }
897   
898  58740 if (functionType == null) {
899    // Find the type of any overridden function.
900  58511 Node ownerNode = NodeUtil.getBestLValueOwner(lvalueNode);
901  58511 String ownerName = NodeUtil.getBestLValueName(ownerNode);
902  58511 Var ownerVar = null;
903  58511 String propName = null;
904  58511 ObjectType ownerType = null;
905  58511 if (ownerName != null) {
906  14476 ownerVar = scope.getVar(ownerName);
907  14476 if (ownerVar != null) {
908  13851 ownerType = ObjectType.cast(ownerVar.getType());
909    }
910  14476 if (name != null) {
911  14462 propName = name.substring(ownerName.length() + 1);
912    }
913    }
914   
915  58511 FunctionType overriddenType = null;
916  58511 if (ownerType != null && propName != null) {
917  12143 overriddenType = findOverriddenFunction(ownerType, propName);
918    }
919   
920  58511 FunctionTypeBuilder builder =
921    new FunctionTypeBuilder(name, compiler, errorRoot, sourceName,
922    scope)
923    .setContents(getFunctionAnalysisResults(fnRoot))
924    .inferFromOverriddenFunction(overriddenType, parametersNode)
925    .inferTemplateTypeName(info)
926    .inferReturnType(info)
927    .inferInheritance(info);
928   
929    // Infer the context type.
930  58511 boolean searchedForThisType = false;
931  58511 if (ownerType != null && ownerType.isFunctionPrototypeType() &&
932    ownerType.getOwnerFunction().hasInstanceType()) {
933  10760 builder.inferThisType(
934    info, ownerType.getOwnerFunction().getInstanceType());
935  10760 searchedForThisType = true;
936  47751 } else if (ownerNode != null && ownerNode.isThis()) {
937    // If 'this' has a type, use that instead.
938    // This is a hack, necessary because CollectProperties (below)
939    // doesn't run with the scope that it's building,
940    // so scope.getTypeOfThis() will be wrong.
941  30 JSType injectedThisType = ownerNode.getJSType();
942  30 builder.inferThisType(
943    info,
944  30 injectedThisType == null ?
945    scope.getTypeOfThis() : injectedThisType);
946  30 searchedForThisType = true;
947    }
948   
949  58511 if (!searchedForThisType) {
950  47721 builder.inferThisType(info);
951    }
952   
953  58511 functionType = builder
954    .inferParameterTypes(parametersNode, info)
955    .buildAndRegister();
956    }
957    }
958   
959    // all done
960  58808 return functionType;
961    }
962   
963    /**
964    * Find the function that's being overridden on this type, if any.
965    */
 
966  12143 toggle private FunctionType findOverriddenFunction(
967    ObjectType ownerType, String propName) {
968    // First, check to see if the property is implemented
969    // on a superclass.
970  12143 JSType propType = ownerType.getPropertyType(propName);
971  12143 if (propType != null && propType.isFunctionType()) {
972  5090 return propType.toMaybeFunctionType();
973    } else {
974    // If it's not, then check to see if it's implemented
975    // on an implemented interface.
976  7053 for (ObjectType iface :
977    ownerType.getCtorImplementedInterfaces()) {
978  67 propType = iface.getPropertyType(propName);
979  67 if (propType != null && propType.isFunctionType()) {
980  49 return propType.toMaybeFunctionType();
981    }
982    }
983    }
984   
985  7004 return null;
986    }
987   
988    /**
989    * Creates a new enum type, based on the given nodes.
990    *
991    * This handles two cases that are semantically very different, but
992    * are not mutually exclusive:
993    * - An object literal that needs an enum type attached to it.
994    * - An assignment expression with an enum tag in the JsDoc.
995    *
996    * This function will always create an enum type, so only call it if
997    * you're sure that's what you want.
998    *
999    * @param rValue The node of the enum.
1000    * @param name The enum's name
1001    * @param info The {@link JSDocInfo} attached to the enum definition.
1002    * @param lValueNode The node where this function is being
1003    * assigned.
1004    */
 
1005  424 toggle private EnumType createEnumTypeFromNodes(Node rValue, String name,
1006    JSDocInfo info, Node lValueNode) {
1007  424 Preconditions.checkNotNull(info);
1008  424 Preconditions.checkState(info.hasEnumParameterType());
1009   
1010  424 EnumType enumType = null;
1011  424 if (rValue != null && rValue.isQualifiedName()) {
1012    // Handle an aliased enum.
1013  69 Var var = scope.getVar(rValue.getQualifiedName());
1014  69 if (var != null && var.getType() instanceof EnumType) {
1015  69 enumType = (EnumType) var.getType();
1016    }
1017    }
1018   
1019  424 if (enumType == null) {
1020  355 JSType elementsType =
1021    info.getEnumParameterType().evaluate(scope, typeRegistry);
1022  355 enumType = typeRegistry.createEnumType(name, rValue, elementsType);
1023   
1024  355 if (rValue != null && rValue.isObjectLit()) {
1025    // collect enum elements
1026  340 Node key = rValue.getFirstChild();
1027  825 while (key != null) {
1028  485 String keyName = NodeUtil.getStringValue(key);
1029  485 if (keyName == null) {
1030    // GET and SET don't have a String value;
1031  0 compiler.report(
1032    JSError.make(sourceName, key, ENUM_NOT_CONSTANT, keyName));
1033  485 } else if (!codingConvention.isValidEnumKey(keyName)) {
1034  11 compiler.report(
1035    JSError.make(sourceName, key, ENUM_NOT_CONSTANT, keyName));
1036    } else {
1037  474 enumType.defineElement(keyName, key);
1038    }
1039  485 key = key.getNext();
1040    }
1041    }
1042    }
1043   
1044  424 if (name != null && scope.isGlobal()) {
1045  419 typeRegistry.declareType(name, enumType.getElementsType());
1046    }
1047   
1048  424 return enumType;
1049    }
1050   
1051    /**
1052    * Defines a typed variable. The defining node will be annotated with the
1053    * variable's type or {@code null} if its type is inferred.
1054    * @param name the defining node. It must be a {@link Token#NAME}.
1055    * @param parent the {@code name}'s parent.
1056    * @param type the variable's type. It may be {@code null}, in which case
1057    * the variable's type will be inferred.
1058    */
 
1059  54997 toggle private void defineSlot(Node name, Node parent, JSType type) {
1060  54997 defineSlot(name, parent, type, type == null);
1061    }
1062   
1063    /**
1064    * Defines a typed variable. The defining node will be annotated with the
1065    * variable's type of {@link JSTypeNative#UNKNOWN_TYPE} if its type is
1066    * inferred.
1067    *
1068    * Slots may be any variable or any qualified name in the global scope.
1069    *
1070    * @param n the defining NAME or GETPROP node.
1071    * @param parent the {@code n}'s parent.
1072    * @param type the variable's type. It may be {@code null} if
1073    * {@code inferred} is {@code true}.
1074    */
 
1075  146916 toggle void defineSlot(Node n, Node parent, JSType type, boolean inferred) {
1076  146916 Preconditions.checkArgument(inferred || type != null);
1077   
1078    // Only allow declarations of NAMEs and qualified names.
1079    // Object literal keys will have to compute their names themselves.
1080  146916 if (n.isName()) {
1081  99323 Preconditions.checkArgument(
1082    parent.isFunction() ||
1083    parent.isVar() ||
1084    parent.isParamList() ||
1085    parent.isCatch());
1086    } else {
1087  47593 Preconditions.checkArgument(
1088    n.isGetProp() &&
1089    (parent.isAssign() ||
1090    parent.isExprResult()));
1091    }
1092  146916 defineSlot(n, parent, n.getQualifiedName(), type, inferred);
1093    }
1094   
1095   
1096    /**
1097    * Defines a symbol in the current scope.
1098    *
1099    * @param n the defining NAME or GETPROP or object literal key node.
1100    * @param parent the {@code n}'s parent.
1101    * @param variableName The name that this should be known by.
1102    * @param type the variable's type. It may be {@code null} if
1103    * {@code inferred} is {@code true}.
1104    * @param inferred Whether the type is inferred or declared.
1105    */
 
1106  148283 toggle void defineSlot(Node n, Node parent, String variableName,
1107    JSType type, boolean inferred) {
1108  148283 Preconditions.checkArgument(!variableName.isEmpty());
1109   
1110  148283 boolean isGlobalVar = n.isName() && scope.isGlobal();
1111  148283 boolean shouldDeclareOnGlobalThis =
1112    isGlobalVar &&
1113    (parent.isVar() ||
1114    parent.isFunction());
1115   
1116    // If n is a property, then we should really declare it in the
1117    // scope where the root object appears. This helps out people
1118    // who declare "global" names in an anonymous namespace.
1119  148283 Scope scopeToDeclareIn = scope;
1120  148283 if (n.isGetProp() && !scope.isGlobal() &&
1121    isQnameRootedInGlobalScope(n)) {
1122  22 Scope globalScope = scope.getGlobalScope();
1123   
1124    // don't try to declare in the global scope if there's
1125    // already a symbol there with this name.
1126  22 if (!globalScope.isDeclared(variableName, false)) {
1127  18 scopeToDeclareIn = scope.getGlobalScope();
1128    }
1129    }
1130   
1131    // The input may be null if we are working with a AST snippet. So read
1132    // the extern info from the node.
1133  148283 boolean isExtern = n.isFromExterns();
1134  148283 Var newVar = null;
1135   
1136    // declared in closest scope?
1137  148283 CompilerInput input = compiler.getInput(inputId);
1138  148283 if (scopeToDeclareIn.isDeclared(variableName, false)) {
1139  26397 Var oldVar = scopeToDeclareIn.getVar(variableName);
1140  26397 newVar = validator.expectUndeclaredVariable(
1141    sourceName, input, n, parent, oldVar, variableName, type);
1142    } else {
1143  121886 if (type != null) {
1144  118464 setDeferredType(n, type);
1145    }
1146   
1147  121886 newVar =
1148    scopeToDeclareIn.declare(variableName, n, type, input, inferred);
1149   
1150  121886 if (type instanceof EnumType) {
1151  417 Node initialValue = newVar.getInitialValue();
1152  417 boolean isValidValue = initialValue != null &&
1153    (initialValue.isObjectLit() ||
1154    initialValue.isQualifiedName());
1155  417 if (!isValidValue) {
1156  15 compiler.report(JSError.make(sourceName, n, ENUM_INITIALIZER));
1157    }
1158    }
1159    }
1160   
1161    // We need to do some additional work for constructors and interfaces.
1162  148283 FunctionType fnType = JSType.toMaybeFunctionType(type);
1163  148283 if (fnType != null &&
1164    // We don't want to look at empty function types.
1165    !type.isEmptyType()) {
1166   
1167    // We want to make sure that when we declare a new instance type
1168    // (with @constructor) that there's actually a ctor for it.
1169    // This doesn't apply to structural constructors (like
1170    // function(new:Array). Checking the constructed type against
1171    // the variable name is a sufficient check for this.
1172  73421 if ((fnType.isConstructor() || fnType.isInterface()) &&
1173    variableName.equals(fnType.getReferenceName())) {
1174  37547 finishConstructorDefinition(n, variableName, fnType, scopeToDeclareIn,
1175    input, newVar);
1176    }
1177    }
1178   
1179  148283 if (shouldDeclareOnGlobalThis) {
1180  54035 ObjectType globalThis =
1181    typeRegistry.getNativeObjectType(GLOBAL_THIS);
1182  54035 if (inferred) {
1183  2068 globalThis.defineInferredProperty(variableName,
1184  2068 type == null ?
1185    getNativeType(JSTypeNative.NO_TYPE) :
1186    type,
1187    n);
1188    } else {
1189  51967 globalThis.defineDeclaredProperty(variableName, type, n);
1190    }
1191    }
1192   
1193  148283 if (isGlobalVar && "Window".equals(variableName)
1194    && type != null
1195    && type.isFunctionType()
1196    && type.isConstructor()) {
1197  176 FunctionType globalThisCtor =
1198    typeRegistry.getNativeObjectType(GLOBAL_THIS).getConstructor();
1199  176 globalThisCtor.getInstanceType().clearCachedValues();
1200  176 globalThisCtor.getPrototype().clearCachedValues();
1201  176 globalThisCtor
1202    .setPrototypeBasedOn((type.toMaybeFunctionType()).getInstanceType());
1203    }
1204    }
1205   
 
1206  37547 toggle private void finishConstructorDefinition(
1207    Node n, String variableName, FunctionType fnType,
1208    Scope scopeToDeclareIn, CompilerInput input, Var newVar) {
1209    // Declare var.prototype in the scope chain.
1210  37547 FunctionType superClassCtor = fnType.getSuperClassConstructor();
1211  37547 Property prototypeSlot = fnType.getSlot("prototype");
1212   
1213    // When we declare the function prototype implicitly, we
1214    // want to make sure that the function and its prototype
1215    // are declared at the same node. We also want to make sure
1216    // that the if a symbol has both a Var and a JSType, they have
1217    // the same node.
1218    //
1219    // This consistency is helpful to users of SymbolTable,
1220    // because everything gets declared at the same place.
1221  37547 prototypeSlot.setNode(n);
1222   
1223  37547 String prototypeName = variableName + ".prototype";
1224   
1225    // There are some rare cases where the prototype will already
1226    // be declared. See TypedScopeCreatorTest#testBogusPrototypeInit.
1227    // Fortunately, other warnings will complain if this happens.
1228  37547 Var prototypeVar = scopeToDeclareIn.getVar(prototypeName);
1229  37547 if (prototypeVar != null && prototypeVar.scope == scopeToDeclareIn) {
1230  20738 scopeToDeclareIn.undeclare(prototypeVar);
1231    }
1232   
1233  37547 scopeToDeclareIn.declare(prototypeName,
1234    n, prototypeSlot.getType(), input,
1235    /* declared iff there's an explicit supertype */
1236    superClassCtor == null ||
1237    superClassCtor.getInstanceType().isEquivalentTo(
1238    getNativeType(OBJECT_TYPE)));
1239   
1240    // Make sure the variable is initialized to something if
1241    // it constructs itself.
1242  37547 if (newVar.getInitialValue() == null &&
1243    !n.isFromExterns()) {
1244  8 compiler.report(
1245    JSError.make(sourceName, n,
1246  8 fnType.isConstructor() ?
1247    CTOR_INITIALIZER : IFACE_INITIALIZER,
1248    variableName));
1249    }
1250    }
1251   
1252    /**
1253    * Check if the given node is a property of a name in the global scope.
1254    */
 
1255  217 toggle private boolean isQnameRootedInGlobalScope(Node n) {
1256  217 Scope scope = getQnameRootScope(n);
1257  217 return scope != null && scope.isGlobal();
1258    }
1259   
1260    /**
1261    * Return the scope for the name of the given node.
1262    */
 
1263  217 toggle private Scope getQnameRootScope(Node n) {
1264  217 Node root = NodeUtil.getRootOfQualifiedName(n);
1265  217 if (root.isName()) {
1266  64 Var var = scope.getVar(root.getString());
1267  64 if (var != null) {
1268  64 return var.getScope();
1269    }
1270    }
1271  153 return null;
1272    }
1273   
1274    /**
1275    * Look for a type declaration on a property assignment
1276    * (in an ASSIGN or an object literal key).
1277    *
1278    * @param info The doc info for this property.
1279    * @param lValue The l-value node.
1280    * @param rValue The node that {@code n} is being initialized to,
1281    * or {@code null} if this is a stub declaration.
1282    */
 
1283  66279 toggle private JSType getDeclaredType(String sourceName, JSDocInfo info,
1284    Node lValue, @Nullable Node rValue) {
1285  66279 if (info != null && info.hasType()) {
1286  38275 return getDeclaredTypeInAnnotation(sourceName, lValue, info);
1287  28004 } else if (rValue != null && rValue.isFunction() &&
1288    shouldUseFunctionLiteralType(
1289    JSType.toMaybeFunctionType(rValue.getJSType()), info, lValue)) {
1290  16315 return rValue.getJSType();
1291  11689 } else if (info != null) {
1292  1470 if (info.hasEnumParameterType()) {
1293  417 if (rValue != null && rValue.isObjectLit()) {
1294  333 return rValue.getJSType();
1295    } else {
1296  84 return createEnumTypeFromNodes(
1297    rValue, lValue.getQualifiedName(), info, lValue);
1298    }
1299  1053 } else if (info.isConstructor() || info.isInterface()) {
1300  115 return createFunctionTypeFromNodes(
1301    rValue, lValue.getQualifiedName(), info, lValue);
1302    } else {
1303    // Check if this is constant, and if it has a known type.
1304  938 if (info.isConstant()) {
1305  187 JSType knownType = null;
1306  187 if (rValue != null) {
1307  132 JSDocInfo rValueInfo = rValue.getJSDocInfo();
1308  132 if (rValueInfo != null && rValueInfo.hasType()) {
1309    // If rValue has a type-cast, we use the type in the type-cast.
1310  2 return rValueInfo.getType().evaluate(scope, typeRegistry);
1311  130 } else if (rValue.getJSType() != null
1312    && !rValue.getJSType().isUnknownType()) {
1313    // If rValue's type was already computed during scope creation,
1314    // then we can safely use that.
1315  95 return rValue.getJSType();
1316  35 } else if (rValue.isOr()) {
1317    // Check for a very specific JS idiom:
1318    // var x = x || TYPE;
1319    // This is used by Closure's base namespace for esoteric
1320    // reasons.
1321  8 Node firstClause = rValue.getFirstChild();
1322  8 Node secondClause = firstClause.getNext();
1323  8 boolean namesMatch = firstClause.isName()
1324    && lValue.isName()
1325    && firstClause.getString().equals(lValue.getString());
1326  8 if (namesMatch && secondClause.getJSType() != null
1327    && !secondClause.getJSType().isUnknownType()) {
1328  6 return secondClause.getJSType();
1329    }
1330    }
1331    }
1332    }
1333    }
1334    }
1335   
1336  11054 return getDeclaredTypeInAnnotation(sourceName, lValue, info);
1337    }
1338   
 
1339  168 toggle private FunctionType getFunctionType(@Nullable Var v) {
1340  168 JSType t = v == null ? null : v.getType();
1341  168 ObjectType o = t == null ? null : t.dereference();
1342  168 return JSType.toMaybeFunctionType(o);
1343    }
1344   
1345    /**
1346    * Look for calls that set a delegate method's calling convention.
1347    */
 
1348  3382 toggle private void checkForCallingConventionDefiningCalls(
1349    Node n, Map<String, String> delegateCallingConventions) {
1350  3382 codingConvention.checkForCallingConventionDefiningCalls(n,
1351    delegateCallingConventions);
1352    }
1353   
1354    /**
1355    * Look for class-defining calls.
1356    * Because JS has no 'native' syntax for defining classes,
1357    * this is often very coding-convention dependent and business-logic heavy.
1358    */
 
1359  3382 toggle private void checkForClassDefiningCalls(
1360    NodeTraversal t, Node n, Node parent) {
1361  3382 SubclassRelationship relationship =
1362    codingConvention.getClassesDefinedByCall(n);
1363  3382 if (relationship != null) {
1364  84 FunctionType superCtor = getFunctionType(
1365    scope.getVar(relationship.superclassName));
1366  84 FunctionType subCtor = getFunctionType(
1367    scope.getVar(relationship.subclassName));
1368  84 if (superCtor != null && superCtor.isConstructor() &&
1369    subCtor != null && subCtor.isConstructor()) {
1370  84 ObjectType superClass = superCtor.getInstanceType();
1371  84 ObjectType subClass = subCtor.getInstanceType();
1372   
1373    // superCtor and subCtor might be structural constructors
1374    // (like {function(new:Object)}) so we need to resolve them back
1375    // to the original ctor objects.
1376  84 superCtor = superClass.getConstructor();
1377  84 subCtor = subClass.getConstructor();
1378   
1379  84 if (relationship.type == SubclassType.INHERITS &&
1380    !superClass.isEmptyType() && !subClass.isEmptyType()) {
1381  84 validator.expectSuperType(t, n, superClass, subClass);
1382    }
1383   
1384  84 if (superCtor != null && subCtor != null) {
1385  80 codingConvention.applySubclassRelationship(
1386    superCtor, subCtor, relationship.type);
1387    }
1388    }
1389    }
1390   
1391  3382 String singletonGetterClassName =
1392    codingConvention.getSingletonGetterClassName(n);
1393  3382 if (singletonGetterClassName != null) {
1394  5 ObjectType objectType = ObjectType.cast(
1395    typeRegistry.getType(singletonGetterClassName));
1396  5 if (objectType != null) {
1397  5 FunctionType functionType = objectType.getConstructor();
1398   
1399  5 if (functionType != null) {
1400  5 FunctionType getterType =
1401    typeRegistry.createFunctionType(objectType);
1402  5 codingConvention.applySingletonGetter(functionType, getterType,
1403    objectType);
1404    }
1405    }
1406    }
1407   
1408  3382 DelegateRelationship delegateRelationship =
1409    codingConvention.getDelegateRelationship(n);
1410  3382 if (delegateRelationship != null) {
1411  0 applyDelegateRelationship(delegateRelationship);
1412    }
1413   
1414  3382 ObjectLiteralCast objectLiteralCast =
1415    codingConvention.getObjectLiteralCast(n);
1416  3382 if (objectLiteralCast != null) {
1417  16 if (objectLiteralCast.diagnosticType == null) {
1418  14 ObjectType type = ObjectType.cast(
1419    typeRegistry.getType(objectLiteralCast.typeName));
1420  14 if (type != null && type.getConstructor() != null) {
1421  12 setDeferredType(objectLiteralCast.objectNode, type);
1422    } else {
1423  2 compiler.report(JSError.make(t.getSourceName(), n,
1424    CONSTRUCTOR_EXPECTED));
1425    }
1426    } else {
1427  2 compiler.report(JSError.make(t.getSourceName(), n,
1428    objectLiteralCast.diagnosticType));
1429    }
1430    }
1431    }
1432   
1433    /**
1434    * Apply special properties that only apply to delegates.
1435    */
 
1436  0 toggle private void applyDelegateRelationship(
1437    DelegateRelationship delegateRelationship) {
1438  0 ObjectType delegatorObject = ObjectType.cast(
1439    typeRegistry.getType(delegateRelationship.delegator));
1440  0 ObjectType delegateBaseObject = ObjectType.cast(
1441    typeRegistry.getType(delegateRelationship.delegateBase));
1442  0 ObjectType delegateSuperObject = ObjectType.cast(
1443    typeRegistry.getType(codingConvention.getDelegateSuperclassName()));
1444  0 if (delegatorObject != null &&
1445    delegateBaseObject != null &&
1446    delegateSuperObject != null) {
1447  0 FunctionType delegatorCtor = delegatorObject.getConstructor();
1448  0 FunctionType delegateBaseCtor = delegateBaseObject.getConstructor();
1449  0 FunctionType delegateSuperCtor = delegateSuperObject.getConstructor();
1450   
1451  0 if (delegatorCtor != null && delegateBaseCtor != null &&
1452    delegateSuperCtor != null) {
1453  0 FunctionParamBuilder functionParamBuilder =
1454    new FunctionParamBuilder(typeRegistry);
1455  0 functionParamBuilder.addRequiredParams(
1456    getNativeType(U2U_CONSTRUCTOR_TYPE));
1457  0 FunctionType findDelegate = typeRegistry.createFunctionType(
1458    typeRegistry.createDefaultObjectUnion(delegateBaseObject),
1459    functionParamBuilder.build());
1460   
1461  0 FunctionType delegateProxy = typeRegistry.createConstructorType(
1462    delegateBaseObject.getReferenceName() + DELEGATE_PROXY_SUFFIX,
1463    null, null, null, null);
1464  0 delegateProxy.setPrototypeBasedOn(delegateBaseObject);
1465   
1466  0 codingConvention.applyDelegateRelationship(
1467    delegateSuperObject, delegateBaseObject, delegatorObject,
1468    delegateProxy, findDelegate);
1469  0 delegateProxyPrototypes.add(delegateProxy.getPrototype());
1470    }
1471    }
1472    }
1473   
1474    /**
1475    * Declare the symbol for a qualified name in the global scope.
1476    *
1477    * @param info The doc info for this property.
1478    * @param n A top-level GETPROP node (it should not be contained inside
1479    * another GETPROP).
1480    * @param parent The parent of {@code n}.
1481    * @param rhsValue The node that {@code n} is being initialized to,
1482    * or {@code null} if this is a stub declaration.
1483    */
 
1484  51025 toggle void maybeDeclareQualifiedName(NodeTraversal t, JSDocInfo info,
1485    Node n, Node parent, Node rhsValue) {
1486  51025 Node ownerNode = n.getFirstChild();
1487  51025 String ownerName = ownerNode.getQualifiedName();
1488  51025 String qName = n.getQualifiedName();
1489  51025 String propName = n.getLastChild().getString();
1490  51025 Preconditions.checkArgument(qName != null && ownerName != null);
1491   
1492    // Precedence of type information on GETPROPs:
1493    // 1) @type annotation / @enum annotation
1494    // 2) ASSIGN to FUNCTION literal
1495    // 3) @param/@return annotation (with no function literal)
1496    // 4) ASSIGN to something marked @const
1497    // 5) ASSIGN to anything else
1498    //
1499    // 1, 3, and 4 are declarations, 5 is inferred, and 2 is a declaration iff
1500    // the function has JsDoc or has not been declared before.
1501    //
1502    // FUNCTION literals are special because TypedScopeCreator is very smart
1503    // about getting as much type information as possible for them.
1504   
1505    // Determining type for #1 + #2 + #3 + #4
1506  51025 JSType valueType = getDeclaredType(t.getSourceName(), info, n, rhsValue);
1507  51025 if (valueType == null && rhsValue != null) {
1508    // Determining type for #5
1509  2329 valueType = rhsValue.getJSType();
1510    }
1511   
1512    // Function prototypes are special.
1513    // It's a common JS idiom to do:
1514    // F.prototype = { ... };
1515    // So if F does not have an explicitly declared super type,
1516    // allow F.prototype to be redefined arbitrarily.
1517  51025 if ("prototype".equals(propName)) {
1518  229 Var qVar = scope.getVar(qName);
1519  229 if (qVar != null) {
1520    // If the programmer has declared that F inherits from Super,
1521    // and they assign F.prototype to an object literal,
1522    // then they are responsible for making sure that the object literal's
1523    // implicit prototype is set up appropriately. We just obey
1524    // the @extends tag.
1525  189 ObjectType qVarType = ObjectType.cast(qVar.getType());
1526  189 if (qVarType != null &&
1527    rhsValue != null &&
1528    rhsValue.isObjectLit()) {
1529  111 typeRegistry.resetImplicitPrototype(
1530    rhsValue.getJSType(), qVarType.getImplicitPrototype());
1531  78 } else if (!qVar.isTypeInferred()) {
1532    // If the programmer has declared that F inherits from Super,
1533    // and they assign F.prototype to some arbitrary expression,
1534    // there's not much we can do. We just ignore the expression,
1535    // and hope they've annotated their code in a way to tell us
1536    // what props are going to be on that prototype.
1537  30 return;
1538    }
1539  159 if (qVar.getScope() == scope) {
1540  157 scope.undeclare(qVar);
1541    }
1542    }
1543    }
1544   
1545  50995 if (valueType == null) {
1546  3530 if (parent.isExprResult()) {
1547  3232 stubDeclarations.add(new StubDeclaration(
1548    n,
1549    t.getInput() != null && t.getInput().isExtern(),
1550    ownerName));
1551    }
1552   
1553  3530 return;
1554    }
1555   
1556  47465 boolean inferred = isQualifiedNameInferred(
1557    qName, n, info, rhsValue, valueType);
1558  47465 if (!inferred) {
1559  45453 ObjectType ownerType = getObjectSlot(ownerName);
1560  45453 if (ownerType != null) {
1561    // Only declare this as an official property if it has not been
1562    // declared yet.
1563  42744 boolean isExtern = t.getInput() != null && t.getInput().isExtern();
1564  42744 if ((!ownerType.hasOwnProperty(propName) ||
1565    ownerType.isPropertyTypeInferred(propName)) &&
1566    ((isExtern && !ownerType.isNativeObjectType()) ||
1567    !ownerType.isInstanceType())) {
1568    // If the property is undeclared or inferred, declare it now.
1569  37659 ownerType.defineDeclaredProperty(propName, valueType, n);
1570    }
1571    }
1572   
1573    // If the property is already declared, the error will be
1574    // caught when we try to declare it in the current scope.
1575  45453 defineSlot(n, parent, valueType, inferred);
1576  2012 } else if (rhsValue != null && rhsValue.isTrue()) {
1577    // We declare these for delegate proxy method properties.
1578  26 FunctionType ownerType =
1579    JSType.toMaybeFunctionType(getObjectSlot(ownerName));
1580  26 if (ownerType != null) {
1581  0 JSType ownerTypeOfThis = ownerType.getTypeOfThis();
1582  0 String delegateName = codingConvention.getDelegateSuperclassName();
1583  0 JSType delegateType = delegateName == null ?
1584    null : typeRegistry.getType(delegateName);
1585  0 if (delegateType != null &&
1586    ownerTypeOfThis.isSubtype(delegateType)) {
1587  0 defineSlot(n, parent, getNativeType(BOOLEAN_TYPE), true);
1588    }
1589    }
1590    }
1591    }
1592   
1593    /**
1594    * Determines whether a qualified name is inferred.
1595    * NOTE(nicksantos): Determining whether a property is declared or not
1596    * is really really obnoxious.
1597    *
1598    * The problem is that there are two (equally valid) coding styles:
1599    *
1600    * (function() {
1601    * /* The authoritative definition of goog.bar. /
1602    * goog.bar = function() {};
1603    * })();
1604    *
1605    * function f() {
1606    * goog.bar();
1607    * /* Reset goog.bar to a no-op. /
1608    * goog.bar = function() {};
1609    * }
1610    *
1611    * In a dynamic language with first-class functions, it's very difficult
1612    * to know which one the user intended without looking at lots of
1613    * contextual information (the second example demonstrates a small case
1614    * of this, but there are some really pathological cases as well).
1615    *
1616    * The current algorithm checks if either the declaration has
1617    * JsDoc type information, or @const with a known type,
1618    * or a function literal with a name we haven't seen before.
1619    */
 
1620  47465 toggle private boolean isQualifiedNameInferred(
1621    String qName, Node n, JSDocInfo info,
1622    Node rhsValue, JSType valueType) {
1623  47465 if (valueType == null) {
1624  0 return true;
1625    }
1626   
1627  47465 boolean inferred = true;
1628  47465 if (info != null) {
1629  40451 inferred = !(info.hasType()
1630    || info.hasEnumParameterType()
1631    || (info.isConstant() && valueType != null
1632    && !valueType.isUnknownType())
1633    || FunctionTypeBuilder.isFunctionTypeDeclaration(info));
1634    }
1635   
1636  47465 if (inferred && rhsValue != null && rhsValue.isFunction()) {
1637  5859 if (info != null) {
1638  746 return false;
1639  5113 } else if (!scope.isDeclared(qName, false) &&
1640    n.isUnscopedQualifiedName()) {
1641   
1642    // Check if this is in a conditional block.
1643    // Functions assigned in conditional blocks are inferred.
1644  5089 for (Node current = n.getParent();
1645  15289 !(current.isScript() || current.isFunction());
1646    current = current.getParent()) {
1647  10202 if (NodeUtil.isControlStructure(current)) {
1648  2 return true;
1649    }
1650    }
1651   
1652    // Check if this is assigned in an inner scope.
1653    // Functions assigned in inner scopes are inferred.
1654  5087 AstFunctionContents contents =
1655    getFunctionAnalysisResults(scope.getRootNode());
1656  5087 if (contents == null ||
1657    !contents.getEscapedQualifiedNames().contains(qName)) {
1658  5085 return false;
1659    }
1660    }
1661    }
1662  41632 return inferred;
1663    }
1664   
1665    /**
1666    * Find the ObjectType associated with the given slot.
1667    * @param slotName The name of the slot to find the type in.
1668    * @return An object type, or null if this slot does not contain an object.
1669    */
 
1670  47457 toggle private ObjectType getObjectSlot(String slotName) {
1671  47457 Var ownerVar = scope.getVar(slotName);
1672  47457 if (ownerVar != null) {
1673  46540 JSType ownerVarType = ownerVar.getType();
1674  46540 return ObjectType.cast(ownerVarType == null ?
1675    null : ownerVarType.restrictByNotNullOrUndefined());
1676    }
1677  917 return null;
1678    }
1679   
1680    /**
1681    * Resolve any stub declarations to unknown types if we could not
1682    * find types for them during traversal.
1683    */
 
1684  65668 toggle void resolveStubDeclarations() {
1685  65668 for (StubDeclaration stub : stubDeclarations) {
1686  3232 Node n = stub.node;
1687  3232 Node parent = n.getParent();
1688  3232 String qName = n.getQualifiedName();
1689  3232 String propName = n.getLastChild().getString();
1690  3232 String ownerName = stub.ownerName;
1691  3232 boolean isExtern = stub.isExtern;
1692   
1693  3232 if (scope.isDeclared(qName, false)) {
1694  1254 continue;
1695    }
1696   
1697    // If we see a stub property, make sure to register this property
1698    // in the type registry.
1699  1978 ObjectType ownerType = getObjectSlot(ownerName);
1700  1978 defineSlot(n, parent, unknownType, true);
1701   
1702  1978 if (ownerType != null &&
1703    (isExtern || ownerType.isFunctionPrototypeType())) {
1704    // If this is a stub for a prototype, just declare it
1705    // as an unknown type. These are seen often in externs.
1706  1728 ownerType.defineInferredProperty(
1707    propName, unknownType, n);
1708    } else {
1709  250 typeRegistry.registerPropertyOnType(
1710  250 propName, ownerType == null ? unknownType : ownerType);
1711    }
1712    }
1713    }
1714   
1715    /**
1716    * Collects all declared properties in a function, and
1717    * resolves them relative to the global scope.
1718    */
 
1719    private final class CollectProperties
1720    extends AbstractShallowStatementCallback {
1721    private final JSType thisType;
1722   
 
1723  6126 toggle CollectProperties(JSType thisType) {
1724  6126 this.thisType = thisType;
1725    }
1726   
 
1727  7730 toggle @Override
1728    public void visit(NodeTraversal t, Node n, Node parent) {
1729  7730 if (n.isExprResult()) {
1730  829 Node child = n.getFirstChild();
1731  829 switch (child.getType()) {
1732  512 case Token.ASSIGN:
1733  512 maybeCollectMember(t, child.getFirstChild(), child,
1734    child.getLastChild());
1735  512 break;
1736  24 case Token.GETPROP:
1737  24 maybeCollectMember(t, child, child, null);
1738  24 break;
1739    }
1740    }
1741    }
1742   
 
1743  536 toggle private void maybeCollectMember(NodeTraversal t,
1744    Node member, Node nodeWithJsDocInfo, @Nullable Node value) {
1745  536 JSDocInfo info = nodeWithJsDocInfo.getJSDocInfo();
1746   
1747    // Do nothing if there is no JSDoc type info, or
1748    // if the node is not a member expression, or
1749    // if the member expression is not of the form: this.someProperty.
1750  536 if (info == null ||
1751    !member.isGetProp() ||
1752    !member.getFirstChild().isThis()) {
1753  370 return;
1754    }
1755   
1756  166 member.getFirstChild().setJSType(thisType);
1757  166 JSType jsType = getDeclaredType(t.getSourceName(), info, member, value);
1758  166 Node name = member.getLastChild();
1759  166 if (jsType != null &&
1760    (name.isName() || name.isString()) &&
1761    thisType.toObjectType() != null) {
1762  121 thisType.toObjectType().defineDeclaredProperty(
1763    name.getString(),
1764    jsType,
1765    member);
1766    }
1767    }
1768    } // end CollectProperties
1769    }
1770   
1771    /**
1772    * A stub declaration without any type information.
1773    */
 
1774    private static final class StubDeclaration {
1775    private final Node node;
1776    private final boolean isExtern;
1777    private final String ownerName;
1778   
 
1779  3232 toggle private StubDeclaration(Node node, boolean isExtern, String ownerName) {
1780  3232 this.node = node;
1781  3232 this.isExtern = isExtern;
1782  3232 this.ownerName = ownerName;
1783    }
1784    }
1785   
1786    /**
1787    * A shallow traversal of the global scope to build up all classes,
1788    * functions, and methods.
1789    */
 
1790    private final class GlobalScopeBuilder extends AbstractScopeBuilder {
1791   
 
1792  7176 toggle private GlobalScopeBuilder(Scope scope) {
1793  7176 super(scope);
1794    }
1795   
1796    /**
1797    * Visit a node in the global scope, and add anything it declares to the
1798    * global symbol table.
1799    *
1800    * @param t The current traversal.
1801    * @param n The node being visited.
1802    * @param parent The parent of n
1803    */
 
1804  501242 toggle @Override public void visit(NodeTraversal t, Node n, Node parent) {
1805  501242 super.visit(t, n, parent);
1806   
1807  501242 switch (n.getType()) {
1808   
1809  12843 case Token.VAR:
1810    // Handle typedefs.
1811  12843 if (n.hasOneChild()) {
1812  12821 checkForTypedef(t, n.getFirstChild(), n.getJSDocInfo());
1813    }
1814  12843 break;
1815    }
1816    }
1817   
 
1818  50109 toggle @Override
1819    void maybeDeclareQualifiedName(
1820    NodeTraversal t, JSDocInfo info,
1821    Node n, Node parent, Node rhsValue) {
1822  50109 checkForTypedef(t, n, info);
1823  50109 super.maybeDeclareQualifiedName(t, info, n, parent, rhsValue);
1824    }
1825   
1826    /**
1827    * Handle typedefs.
1828    * @param t The current traversal.
1829    * @param candidate A qualified name node.
1830    * @param info JSDoc comments.
1831    */
 
1832  62930 toggle private void checkForTypedef(
1833    NodeTraversal t, Node candidate, JSDocInfo info) {
1834  62930 if (info == null || !info.hasTypedefType()) {
1835  62748 return;
1836    }
1837   
1838  182 String typedef = candidate.getQualifiedName();
1839  182 if (typedef == null) {
1840  0 return;
1841    }
1842   
1843    // TODO(nicksantos|user): This is a terrible, terrible hack
1844    // to bail out on recursive typedefs. We'll eventually need
1845    // to handle these properly.
1846  182 typeRegistry.declareType(typedef, unknownType);
1847   
1848  182 JSType realType = info.getTypedefType().evaluate(scope, typeRegistry);
1849  182 if (realType == null) {
1850  0 compiler.report(
1851    JSError.make(
1852    t.getSourceName(), candidate, MALFORMED_TYPEDEF, typedef));
1853    }
1854   
1855  182 typeRegistry.overwriteDeclaredType(typedef, realType);
1856  182 if (candidate.isGetProp()) {
1857  162 defineSlot(candidate, candidate.getParent(),
1858    getNativeType(NO_TYPE), false);
1859    }
1860    }
1861    } // end GlobalScopeBuilder
1862   
1863    /**
1864    * A shallow traversal of a local scope to find all arguments and
1865    * local variables.
1866    */
 
1867    private final class LocalScopeBuilder extends AbstractScopeBuilder {
1868    /**
1869    * @param scope The scope that we're building.
1870    */
 
1871  58492 toggle private LocalScopeBuilder(Scope scope) {
1872  58492 super(scope);
1873    }
1874   
1875    /**
1876    * Traverse the scope root and build it.
1877    */
 
1878  58492 toggle void build() {
1879  58492 NodeTraversal.traverse(compiler, scope.getRootNode(), this);
1880   
1881  58492 AstFunctionContents contents =
1882    getFunctionAnalysisResults(scope.getRootNode());
1883  58492 if (contents != null) {
1884  58492 for (String varName : contents.getEscapedVarNames()) {
1885  35 Var v = scope.getVar(varName);
1886  35 Preconditions.checkState(v.getScope() == scope);
1887  35 v.markEscaped();
1888    }
1889   
1890  58492 for (Multiset.Entry<String> entry :
1891    contents.getAssignedNameCounts().entrySet()) {
1892  45220 Var v = scope.getVar(entry.getElement());
1893  45220 Preconditions.checkState(v.getScope() == scope);
1894  45220 if (entry.getCount() == 1) {
1895  44919 v.markAssignedExactlyOnce();
1896    }
1897    }
1898    }
1899    }
1900   
1901    /**
1902    * Visit a node in a local scope, and add any local variables or catch
1903    * parameters into the local symbol table.
1904    *
1905    * @param t The node traversal.
1906    * @param n The node being visited.
1907    * @param parent The parent of n
1908    */
 
1909  312165 toggle @Override public void visit(NodeTraversal t, Node n, Node parent) {
1910  58492 if (n == scope.getRootNode()) return;
1911   
1912  253673 if (n.isParamList() && parent == scope.getRootNode()) {
1913  58492 handleFunctionInputs(parent);
1914  58492 return;
1915    }
1916   
1917  195181 super.visit(t, n, parent);
1918    }
1919   
1920    /** Handle bleeding functions and function parameters. */
 
1921  58492 toggle private void handleFunctionInputs(Node fnNode) {
1922    // Handle bleeding functions.
1923  58492 Node fnNameNode = fnNode.getFirstChild();
1924  58492 String fnName = fnNameNode.getString();
1925  58492 if (!fnName.isEmpty()) {
1926  41368 Scope.Var fnVar = scope.getVar(fnName);
1927  41368 if (fnVar == null ||
1928    // Make sure we're not touching a native function. Native
1929    // functions aren't bleeding, but may not have a declaration
1930    // node.
1931    (fnVar.getNameNode() != null &&
1932    // Make sure that the function is actually bleeding by checking
1933    // if has already been declared.
1934    fnVar.getInitialValue() != fnNode)) {
1935  50 defineSlot(fnNameNode, fnNode, fnNode.getJSType(), false);
1936    }
1937    }
1938   
1939  58492 declareArguments(fnNode);
1940    }
1941   
1942    /**
1943    * Declares all of a function's arguments.
1944    */
 
1945  58492 toggle private void declareArguments(Node functionNode) {
1946  58492 Node astParameters = functionNode.getFirstChild().getNext();
1947  58492 Node iifeArgumentNode = null;
1948   
1949  58492 if (NodeUtil.isCallOrNewTarget(functionNode)) {
1950  56 iifeArgumentNode = functionNode.getNext();
1951    }
1952   
1953  58492 Node body = astParameters.getNext();
1954  58492 FunctionType functionType =
1955    JSType.toMaybeFunctionType(functionNode.getJSType());
1956  58492 if (functionType != null) {
1957  58492 Node jsDocParameters = functionType.getParametersNode();
1958  58492 if (jsDocParameters != null) {
1959  58492 Node jsDocParameter = jsDocParameters.getFirstChild();
1960  58492 for (Node astParameter : astParameters.children()) {
1961  44276 JSType paramType = jsDocParameter == null ?
1962    unknownType : jsDocParameter.getJSType();
1963  44276 boolean inferred = paramType == null || paramType == unknownType;
1964   
1965  44276 if (iifeArgumentNode != null && inferred) {
1966  10 String argumentName = iifeArgumentNode.getQualifiedName();
1967  10 Var argumentVar =
1968  10 argumentName == null || scope.getParent() == null
1969    ? null : scope.getParent().getVar(argumentName);
1970  10 if (argumentVar != null && !argumentVar.isTypeInferred()) {
1971  8 paramType = argumentVar.getType();
1972    }
1973    }
1974   
1975  44276 if (paramType == null) {
1976  0 paramType = unknownType;
1977    }
1978   
1979  44276 defineSlot(astParameter, functionNode, paramType, inferred);
1980   
1981  44276 if (jsDocParameter != null) {
1982  44208 jsDocParameter = jsDocParameter.getNext();
1983    }
1984  44276 if (iifeArgumentNode != null) {
1985  10 iifeArgumentNode = iifeArgumentNode.getNext();
1986    }
1987    }
1988    }
1989    }
1990    } // end declareArguments
1991    } // end LocalScopeBuilder
1992   
1993    /**
1994    * Does a first-order function analysis that just looks at simple things
1995    * like what variables are escaped, and whether 'this' is used.
1996    */
 
1997    private static class FirstOrderFunctionAnalyzer
1998    extends AbstractScopedCallback implements CompilerPass {
1999    private final AbstractCompiler compiler;
2000    private final Map<Node, AstFunctionContents> data;
2001   
 
2002  7176 toggle FirstOrderFunctionAnalyzer(
2003    AbstractCompiler compiler, Map<Node, AstFunctionContents> outParam) {
2004  7176 this.compiler = compiler;
2005  7176 this.data = outParam;
2006    }
2007   
 
2008  7176 toggle @Override public void process(Node externs, Node root) {
2009  7176 if (externs == null) {
2010  0 NodeTraversal.traverse(compiler, root, this);
2011    } else {
2012  7176 NodeTraversal.traverseRoots(
2013    compiler, ImmutableList.of(externs, root), this);
2014    }
2015    }
2016   
 
2017  66006 toggle @Override public void enterScope(NodeTraversal t) {
2018  66006 if (!t.inGlobalScope()) {
2019  58830 Node n = t.getScopeRoot();
2020  58830 data.put(n, new AstFunctionContents(n));
2021    }
2022    }
2023   
 
2024  698255 toggle @Override public void visit(NodeTraversal t, Node n, Node parent) {
2025  698255 if (t.inGlobalScope()) {
2026  477792 return;
2027    }
2028   
2029  220463 if (n.isReturn() && n.getFirstChild() != null) {
2030  2600 data.get(t.getScopeRoot()).recordNonEmptyReturn();
2031    }
2032   
2033  220463 if (t.getScopeDepth() <= 1) {
2034    // The first-order function analyzer looks at two types of variables:
2035    //
2036    // 1) Local variables that are assigned in inner scopes ("escaped vars")
2037    //
2038    // 2) Local variables that are assigned more than once.
2039    //
2040    // We treat all global variables as escaped by default, so there's
2041    // no reason to do this extra computation for them.
2042  0 return;
2043    }
2044   
2045  220463 if (n.isName() && NodeUtil.isLValue(n) &&
2046    // Be careful of bleeding functions, which create variables
2047    // in the inner scope, not the scope where the name appears.
2048    !NodeUtil.isBleedingFunctionName(n)) {
2049  65805 String name = n.getString();
2050  65805 Scope scope = t.getScope();
2051  65805 Var var = scope.getVar(name);
2052  65805 if (var != null) {
2053  46057 Scope ownerScope = var.getScope();
2054  46057 if (ownerScope.isLocal()) {
2055  45976 data.get(ownerScope.getRootNode()).recordAssignedName(name);
2056    }
2057   
2058  46057 if (scope != ownerScope && ownerScope.isLocal()) {
2059  41 data.get(ownerScope.getRootNode()).recordEscapedVarName(name);
2060    }
2061    }
2062  154658 } else if (n.isGetProp() && n.isUnscopedQualifiedName() &&
2063    NodeUtil.isLValue(n)) {
2064  382 String name = NodeUtil.getRootOfQualifiedName(n).getString();
2065  382 Scope scope = t.getScope();
2066  382 Var var = scope.getVar(name);
2067  382 if (var != null) {
2068  378 Scope ownerScope = var.getScope();
2069  378 if (scope != ownerScope && ownerScope.isLocal()) {
2070  6 data.get(ownerScope.getRootNode())
2071    .recordEscapedQualifiedName(n.getQualifiedName());
2072    }
2073    }
2074    }
2075    }
2076    }
2077   
 
2078  122090 toggle private AstFunctionContents getFunctionAnalysisResults(@Nullable Node n) {
2079  122090 if (n == null) {
2080  199 return null;
2081    }
2082   
2083    // Sometimes this will return null in things like
2084    // NameReferenceGraphConstruction that build partial scopes.
2085  121891 return functionAnalysisResults.get(n);
2086    }
2087    }